/*
        Updater For Java Programs 
        
    Copyright (C) 2010, Arttu Viljakainen 
    Published under GNU General Public License V3 
    (see http://www.gnu.org/licenses/licenses.html)
    
    This file is part of Updater For Java Programs.

    Updater For Java Programs is free software: 
    you can redistribute it and/or modify it under the terms of the GNU General 
    Public License as published by the Free Software Foundation, 
    either version 3 of the License, or (at your option) any later version.

    Updater For Java Programs is distributed in the hope that it will be useful, 
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 
    Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Updater for Java Programs. If not, see         
    <http://www.gnu.org/licenses/>.
 */
package updater.control;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

import javax.swing.SwingWorker;

public class FileDownloader extends SwingWorker<UpdateDownloadStatus, Integer> {

	private final String urlToSourceFile;
	private final String urlToDestinationFile;
	private int contentLength;
	private int totalReadBytes;
	private volatile boolean cancelDownload;

	public FileDownloader(String urlToSourceFile, String urlToDestinationFile) {
		this.urlToSourceFile = urlToSourceFile;
		this.urlToDestinationFile = urlToDestinationFile;
		cancelDownload = false;
		contentLength = -1;
		totalReadBytes = 0;
	}

	@Override
	protected UpdateDownloadStatus doInBackground() {

		boolean successful = downloadUpdate(urlToSourceFile, urlToDestinationFile);

		if (successful) {
			return UpdateDownloadStatus.FINISHED_SUCCESSFULLY;
		} else {
			return UpdateDownloadStatus.FAILED;
		}

	}

	public boolean downloadUpdate(String urlToSourceFile, String urlToDestinationFile) {

		URL URLToSourceFile = getSourceURL(urlToSourceFile);
		if (URLToSourceFile == null) {
			System.out.println("Malformed url!");
			return false;
		} 

		FileOutputStream streamToLocalFile = getStreamToTheLocalFile(urlToDestinationFile);

		if (streamToLocalFile == null) {
			System.out.println("Failed to open local file " + urlToDestinationFile + "!");
			return false;
		}

		InputStream inputStreamToSourceFile = openInputStreamToSourceFile(URLToSourceFile);
		if (inputStreamToSourceFile == null) {
			System.out.println("Failed to open stream to source file " + urlToSourceFile + "!");
		}

		BufferedInputStream sourceFileReader = new BufferedInputStream(inputStreamToSourceFile);
		BufferedOutputStream destinationFileWriter = new BufferedOutputStream(streamToLocalFile);

		boolean successfullyDownloaded = downloadFileToLocalDisc(sourceFileReader, destinationFileWriter);
	
		return successfullyDownloaded;
	}

	private URL getSourceURL(String urlString) {

		try {
			URL url = new URL(urlString);
			return url;
		} catch (MalformedURLException mue) {
			mue.printStackTrace();
		}

		return null;
	}

	private FileOutputStream getStreamToTheLocalFile(String destinationUrl) {
		try {
			return new FileOutputStream(destinationUrl);
		} catch (FileNotFoundException fnfe) {
			fnfe.printStackTrace();
		}

		return null;
	}

	private InputStream openInputStreamToSourceFile(URL URLToSourceFile) {

		try {

			URLConnection conn = URLToSourceFile.openConnection();
			contentLength = conn.getContentLength();
			System.out.println("Download size: " + contentLength);

			return conn.getInputStream();

		} catch (IOException ioe) {
			ioe.printStackTrace();
		}

		return null;
	}

	private boolean downloadFileToLocalDisc(BufferedInputStream sourceFileReader, BufferedOutputStream destinationFileWriter) {

		boolean successfullyDownloadedFile = false;

		try {
			int readBytes;
			byte[] block = new byte[128];

			while ((readBytes = sourceFileReader.read(block)) > 0 && !cancelDownload) {
				
				totalReadBytes += readBytes;
				int progress = (int)((1.0 * totalReadBytes / contentLength) * 100);
				System.out.println(progress);
				setProgress(progress);
				destinationFileWriter.write(block, 0, readBytes);
				
			}

			if (cancelDownload) {
				setProgress(100);
			} else {
				successfullyDownloadedFile = true;
			}

		} catch (IOException ioe) {
			ioe.printStackTrace();
		} finally {

			try {
				sourceFileReader.close();
				destinationFileWriter.close();
			} catch (IOException ioe) {
				ioe.printStackTrace();
			}
		}
		
		return successfullyDownloadedFile;
	}

	public void cancelUpdate() {
		cancelDownload = true;
	}

	public static void main(String[] args) {
		
	}

}
